// 控制物体移动
// 控制物体mesh的position属性（mesh继承自Object3d类）
import { useEffect } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GUI } from 'dat.gui';

function App() {
  useEffect(() => {
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(
      45,
      window.innerWidth / window.innerHeight,
      0.1,
      1000
    );
    // 渲染器
    const myrender = new THREE.WebGLRenderer();
    myrender.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(myrender.domElement);

    // 交互
    const controls = new OrbitControls(camera, myrender.domElement);
    controls.enableDamping = true;

    // 摄像头方向
    camera.position.set(0, 30, 50);
    // camera.up.set(0, 0, 1); // 相机方向为z轴向上
    camera.lookAt(0, 0, 0); // 相机俯视原点
    scene.add(camera);

    //一： 太阳系
    const objects = []; // 要更新旋转角度的对象数组
    const solarSystem = new THREE.Object3D();
    scene.add(solarSystem);
    objects.push(solarSystem);

    // 二：创建几何体'太阳'
    // 1、几何体
    const radius = 1;
    const widthSegments = 6;
    const heightSegments = 6;
    const sphereGeometry = new THREE.SphereGeometry(
      radius,
      widthSegments,
      heightSegments
    );

    const sunMaterial = new THREE.MeshPhongMaterial({ emissive: 0xffff00 }); //  phong 材质的 emissive 属性设置为黄色。phong 材质的放射属性（emissive）是基本上不受其他光照影响的固有颜色。光照会被添加到该颜色上。
    const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
    sunMesh.scale.set(5, 5, 5); // 扩大太阳的大小
    objects.push(sunMesh);

    // 2、光源
    const light = new THREE.PointLight(0xffffff, 100, 100);
    sunMesh.add(light); // 光源设置在太阳上

    // 三：创建物体'地球'
    const earthMaterial = new THREE.MeshPhongMaterial({
      color: 0x2233ff,
      emissive: 0x112244,
    });
    const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial);
    earthMesh.position.x = 1;
    objects.push(earthMesh);

    // // 五：添加月亮，让月亮绕地球转，但是月亮不能继承地球的属性，使用上述方法，添加一个局部空间将地球月亮均加入进去
    // 1、地球系
    const earthOrbit = new THREE.Object3D();
    earthOrbit.position.x = 15;
    objects.push(earthOrbit);
    // 2、月亮系
    const moonOrbit = new THREE.Object3D();
    moonOrbit.position.x = 3;
    objects.push(moonOrbit);
    // 3、月亮
    const moonMaterial = new THREE.MeshPhongMaterial({
      color: 0x888888,
      emissive: 0x222222,
    });
    const moonMesh = new THREE.Mesh(sphereGeometry, moonMaterial);
    moonMesh.scale.set(0.5, 0.5, 0.5);
    objects.push(moonMesh);

    earthOrbit.add(earthMesh);
    earthOrbit.add(moonOrbit);
    moonOrbit.add(moonMesh);

    // 四：将太阳、地球系加入到太阳系（空节点--局部空间）中
    solarSystem.add(earthOrbit);
    solarSystem.add(sunMesh);

    // 六：添加平面网格，设置属性
    class AxisGridHelper {
      constructor(node, units = 10) {
        const axes = new THREE.AxesHelper();
        axes.material.depthTest = false;
        axes.renderOrder = 2; // 在网格渲染之后再渲染
        node.add(axes);

        const grid = new THREE.GridHelper(units, units);
        grid.material.depthTest = false;
        grid.renderOrder = 1;
        node.add(grid);

        this.grid = grid;
        this.axes = axes;
        this.visible = false;
      }
      get visible() {
        return this._visible;
      }
      set visible(v) {
        this._visible = v;
        this.grid.visible = v;
        this.axes.visible = v;
      }
    }
    const gui = new GUI();
    function makeAxisGrid(node, label, units) {
      const helper = new AxisGridHelper(node, units);
      gui.add(helper, 'visible').name(label);
    }

    makeAxisGrid(solarSystem, 'solarSystem', 25);
    makeAxisGrid(sunMesh, 'sunMesh');
    makeAxisGrid(earthOrbit, 'earthOrbit');
    makeAxisGrid(earthMesh, 'earthMesh');
    makeAxisGrid(moonOrbit, 'moonOrbit');
    makeAxisGrid(moonMesh, 'moonMesh');
    // 渲染
    function renders() {
      const time = performance.now() * 0.0005; // 乘以 0.001 将毫秒转为秒
      objects.forEach((obj) => {
        obj.rotation.y = time;
      });
      myrender.render(scene, camera);
      requestAnimationFrame(renders); // 会以屏幕刷新率（通常 60 FPS）重复调用传入的函数（renders）
    }
    renders();
  }, []);
  return <div></div>;
}
export default App;
